package com.xuecheng.media.service.jobhandler;

import com.xuecheng.base.utils.Mp4VideoUtil;
import com.xuecheng.media.model.po.MediaProcess;
import com.xuecheng.media.service.MediaFileProcessService;
import com.xuecheng.media.service.MediaFileService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 视频处理任务类
 * @author Mr.M
 * @version 1.0
 * @description TODO
 * @date 2022/10/15 11:58
 */
@Slf4j
@Component
public class VideoTask {

    @Autowired
    MediaFileService mediaFileService;

    @Autowired
    MediaFileProcessService mediaFileProcessService;


    @Value("${videoprocess.ffmpegpath}")
    String ffmpegpath;

    @XxlJob("videoJobHandler")
    public void videoJobHandler() throws Exception {
        //分片广播的重点就在于-->分片参数
        int shardIndex = XxlJobHelper.getShardIndex();//执行器的序号，从0开始
        int shardTotal = XxlJobHelper.getShardTotal();//执行器总数
        System.out.println("shardIndex="+shardIndex+",shardTotal="+shardTotal);

        int processors = Runtime.getRuntime().availableProcessors();

        //查询待处理任务
        List<MediaProcess>mediaProcessList = mediaFileProcessService.getMediaProcessList(shardIndex, shardTotal, processors);
        //创建一个线程池
        int size = mediaProcessList.size();
        ExecutorService executorService = Executors.newFixedThreadPool(size);

        CountDownLatch countDownLatch = new CountDownLatch(size);

        mediaProcessList.forEach(mediaProcess -> {
            //将任务加入线程池
            executorService.execute(()->{
                //任务执行逻辑
                try{
                Long taskId = mediaProcess.getId();
                String fileId = mediaProcess.getFileId();
                //开启任务
                boolean b = mediaFileProcessService.startTask(taskId);
                if(!b){
                    log.debug("抢占任务失败，任务id:{}",taskId);
                    return;
                }
                //执行视频转码
                String bucket = mediaProcess.getBucket();
                String objectName = mediaProcess.getFilePath();
                File file = mediaFileService.downloadFileFromMinIO(bucket, objectName);
                if(file == null){
                    log.debug("下载视频出错，任务id:{},bucket:{},objectName:{}",taskId,bucket,objectName);
                    //保存任务处理失败的结果
                    mediaFileProcessService.saveProcessFinishStatus(taskId,"3",
                            fileId,null,"下载视频到本地失败");

                    return;
                }


                //源avi视频的路径
                String video_path = file.getAbsolutePath();
                //转换后mp4文件的名称
                String mp4_name = fileId +".mp4";
                //转换后mp4文件的路径
                File mp4File = null;
                try {
                    mp4File = File.createTempFile("minio",".mp4");
                }catch (IOException e){
                    log.debug("创建临时文件异常");
                    mediaFileProcessService.saveProcessFinishStatus(taskId,"3",
                            fileId,null,"创建临时文件异常");

                    return ;
                }
               //创建工具类对象
                Mp4VideoUtil videoUtil = new Mp4VideoUtil(ffmpegpath,video_path,mp4File.getName(), mp4File.getAbsolutePath());
                //开始视频转换，成功将返回success
                String result = videoUtil.generateMp4();
                if(!result.equals("success")){
                    log.debug("视频转码失败，原因:{},bucket:{},objectName:{}",result,bucket,objectName);
                    mediaFileProcessService.saveProcessFinishStatus(taskId,"3",
                            fileId,null,"视频转码失败");

                    return ;
                }

                boolean b1 = mediaFileService.addMediaFilesToMinIO(mp4File.getAbsolutePath(),
                        bucket,"video/mp4",getFilePath(fileId, ".mp4"));
               if(!b1){
                   log.debug("上传mp4到minio失败，taskId:{}",taskId);
                   mediaFileProcessService.saveProcessFinishStatus(taskId,"3",
                           fileId,null,"上传mp4到minio失败");

                   return ;
               }
               String url = getFilePath(fileId,".mp4");
                mediaFileProcessService.saveProcessFinishStatus(taskId,"2",
                            fileId,url,null);
                }finally {
                    countDownLatch.countDown();
                }
            });
        });
        // 阻塞,指定最大限制的等待时间，阻塞最多等待一定的时间后就解除阻塞
        countDownLatch.await(30, TimeUnit.MINUTES);
        return ;

    }


    private String getFilePath(String fileMd5, String fileExt){
        return fileMd5.substring(0,1)+"/"+fileMd5.substring(1,2)+"/"+fileMd5+"/"+fileMd5+fileExt;
    }

}
